package cn.gwm.flink.streaming.strategy.termal;

import cn.gwm.flink.streaming.beans.termalRunaway.BmsTrdStrategys;
import cn.gwm.flink.streaming.beans.termalRunaway.WaringTermalDwmWithStragegyEv;
import cn.gwm.flink.streaming.beans.termalRunaway.WaringTermalWithStragegyAndFlagEv;
import cn.gwm.flink.streaming.constant.DefaultConstant;
import cn.gwm.flink.streaming.constant.TermalComparisonTypeEnum;
import cn.gwm.flink.streaming.constant.TermalProcessResult;
import cn.gwm.flink.streaming.constant.TermalRunawayTypeEnum;
import cn.gwm.utils.StreamUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.lang.Dict;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.NumberUtil;
import org.apache.flink.api.common.state.ListState;
import org.apache.flink.api.common.state.State;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 热失控温差异常检测
 * @author GW00283474
 */
public class TermalTemperatureDifferenceEvStrategy implements TermalStrategy{
    @Override
    public Dict check(State state, long timestamp) {
        try {
            WaringTermalWithStragegyAndFlagEv result=new WaringTermalWithStragegyAndFlagEv();
            ListState<WaringTermalDwmWithStragegyEv> listState=(ListState<WaringTermalDwmWithStragegyEv>)state;
            Iterator<WaringTermalDwmWithStragegyEv> recordIterator = listState.get().iterator();
            //如果状态无值，则返回null
            if(!recordIterator.hasNext()){ return  null;}
            //信号集合按照tid做正序排列
            List<WaringTermalDwmWithStragegyEv> recordList = StreamUtil.convertIterator(recordIterator)
                    .sorted(new Comparator<WaringTermalDwmWithStragegyEv>() {
                        @Override
                        public int compare(WaringTermalDwmWithStragegyEv o1, WaringTermalDwmWithStragegyEv o2) {
                            return (int) (o1.getItem_time()- o2.getItem_time());
                        }
                    }).collect(Collectors.toList());
             WaringTermalDwmWithStragegyEv first=recordList.stream().findFirst().get();
            BeanUtil.copyProperties(first,result);
            BmsTrdStrategys temperatureDiffStrategy = first.getBmsTrdStrategies().stream().filter(record -> TermalRunawayTypeEnum.TEMPERATUREDIFFERENCE.getKey().equals(record.getItemType())).findFirst().get();
            //温度状态列表中符合本次处理的所有信号记录集合
            List<WaringTermalDwmWithStragegyEv> handleRecords = recordList.stream().filter(s -> BooleanUtil.and(s.getItem_time() >= first.getItem_time(), s.getItem_time() < timestamp)).collect(Collectors.toList());
            //模组温差校验
            Dict checkDict=tempMaxDeviationRulePattern(handleRecords,temperatureDiffStrategy.getComparisonType(), BigDecimal.valueOf(temperatureDiffStrategy.getThreshold()));
            result.setTemperatureDifferenceWarn(checkDict.get(TermalProcessResult.MATCH,false));
            checkDict.set(TermalProcessResult.CHECK_RECORDS,handleRecords);
            checkDict.set(TermalProcessResult.CHECK_RECORD,result);
            //System.out.println("热失控温差检测对象：vin="+result.getVin()+"----tid="+result.getTid());
            //更新温度信号状态列表
            Stream<WaringTermalDwmWithStragegyEv> stream = StreamUtil.convertIterator(listState.get().iterator());
            List<WaringTermalDwmWithStragegyEv> list=stream.filter(s->NumberUtil.isGreater(new BigDecimal(String.valueOf(s.getItem_time())),new BigDecimal(String.valueOf(first.getItem_time())))).collect(Collectors.toList());
            List<Long> tidList = list.stream().map(WaringTermalDwmWithStragegyEv::getItem_time).collect(Collectors.toList());
            //System.out.println("剩余有效温差信号状态列表tids："+tidList);
            ((ListState<WaringTermalDwmWithStragegyEv>) state).update(list);
            Optional<WaringTermalDwmWithStragegyEv> min = StreamUtil.convertIterator(((ListState<WaringTermalDwmWithStragegyEv>) state).get().iterator()).min(new Comparator<WaringTermalDwmWithStragegyEv>() {
                @Override
                public int compare(WaringTermalDwmWithStragegyEv o1, WaringTermalDwmWithStragegyEv o2) {
                    return (int) (o1.getItem_time() - o2.getItem_time());
                }
            });
            if(min.isPresent()){
                //System.out.println("温差信号状态列表最新最小的tid="+min.get().getTid());
            }else{
                //System.out.println("温差信号状态列表暂无数据");
            }
            return checkDict;
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 模组温差校验
     * @param records 信号集合
     * @param condition 阈值比对条件
     * @param threshold 阈值
     * @return 校验结果 true  false
     * @throws Exception
     */
    private Dict tempMaxDeviationRulePattern(List<WaringTermalDwmWithStragegyEv> records, int condition, BigDecimal threshold) throws Exception{
        List<Boolean> flags=new ArrayList<>(0);
        //最大模组温度
        int maxTemp=Integer.MIN_VALUE;
        //最小模组温度
        int minTemp=Integer.MAX_VALUE;
        //最近tid值
        long recentlyTid=Long.MIN_VALUE;
        for (WaringTermalDwmWithStragegyEv waringTermalDwmWithStragegy: records){
            //模组温差
            double maxTempModuleData = waringTermalDwmWithStragegy.getMaxTempDiff();
            recentlyTid=NumberUtil.max(waringTermalDwmWithStragegy.getItem_time(),recentlyTid);
            maxTemp=Objects.nonNull(waringTermalDwmWithStragegy.getBMS_RMC_ModuleTempMax())?NumberUtil.max(waringTermalDwmWithStragegy.getBMS_RMC_ModuleTempMax(),maxTemp):maxTemp;
            minTemp=Objects.nonNull(waringTermalDwmWithStragegy.getBMS_RMC_ModuleTempMin())?NumberUtil.min(waringTermalDwmWithStragegy.getBMS_RMC_ModuleTempMin(),minTemp):minTemp;
            //如果最大模组温度值为默认缺省值，则不参与计算
            if(DefaultConstant.BMS_RMC_ModuleTemp.intValue()==maxTemp){
                continue ;
            }else{
                if(TermalComparisonTypeEnum.EQ.getKey()==condition){
                    flags.add(NumberUtil.equals(maxTempModuleData,threshold.doubleValue()));
                }
                if(TermalComparisonTypeEnum.LE.getKey() ==condition){
                    flags.add(NumberUtil.isLessOrEqual(new BigDecimal(maxTempModuleData),threshold));
                }
                if(TermalComparisonTypeEnum.LESS.getKey()==condition){
                    flags.add(NumberUtil.isLess(new BigDecimal(maxTempModuleData),threshold));
                }
                if(TermalComparisonTypeEnum.GE.getKey()==condition){
                    flags.add(NumberUtil.isGreaterOrEqual(new BigDecimal(maxTempModuleData),threshold));
                }
                if(TermalComparisonTypeEnum.GREATER.getKey()==condition){
                    flags.add(NumberUtil.isGreater(new BigDecimal(maxTempModuleData),threshold));
                }
                if(TermalComparisonTypeEnum.EXCLUDE.getKey()==condition){
                    flags.add(!NumberUtil.equals(new BigDecimal(maxTempModuleData),threshold));
                }
            }

        }
        boolean match = false;
        if(CollectionUtil.isNotEmpty(flags)){
            match = flags.stream().allMatch(BooleanUtil::isTrue);
        }
        if(match){
            return Dict.of(TermalProcessResult.MATCH,true,
                    TermalProcessResult.MAX_TEMPERATURE,maxTemp,
                    TermalProcessResult.MIN_TEMPERATURE,minTemp,
                    TermalProcessResult.THRESHOLD_TEMPDIFF,threshold,
                    TermalProcessResult.RECENTLY_TID,recentlyTid,
                    TermalProcessResult.STRATEGY_KEY,TermalRunawayTypeEnum.TEMPERATUREDIFFERENCE.getKey(),
                    TermalProcessResult.STRATEGY_DESC,TermalRunawayTypeEnum.TEMPERATUREDIFFERENCE.getValue());
        }
        return Dict.of(TermalProcessResult.MATCH,false,
                TermalProcessResult.THRESHOLD_TEMPDIFF,threshold,
                TermalProcessResult.RECENTLY_TID,recentlyTid,
                TermalProcessResult.STRATEGY_KEY,TermalRunawayTypeEnum.TEMPERATUREDIFFERENCE.getKey(),
                TermalProcessResult.STRATEGY_DESC,TermalRunawayTypeEnum.TEMPERATUREDIFFERENCE.getValue());
    }
}
